home *** CD-ROM | disk | FTP | other *** search
/ Aminet 15 / Aminet 15 - Nov 1996.iso / Aminet / comm / bbs / s342q16.lha / modem.c < prev    next >
C/C++ Source or Header  |  1996-08-29  |  44KB  |  1,895 lines

  1. /*
  2. *       modem.c
  3. *
  4. * modem code for Citadel bulletin board system
  5. * NB: this code is rather machine-dependent:  it will typically
  6. * need some twiddling for each new installation.
  7. *       82Nov05 CrT
  8. *
  9. * now this file is mostly for upper layer modem handling and the protocols,
  10. * so it may need no fiddling.
  11. *       88May07 HAW
  12. */
  13. /*
  14. *       history
  15. *
  16. * 85Nov09 HAW  Warning bell before timeout.
  17. * 85Oct27 HAW  Cermetek support eliminated.
  18. * 85Oct18 HAW  2400 support.
  19. * 85Sep15 HAW  Put limit in ringSysop().
  20. * 85Aug17 HAW  Update for gotCarrier().
  21. * 85Jul05 HAW  Insert fix code (Brian Riley) for 1200 network.
  22. * 85Jun11 HAW  Fix readFile to recognize loss of carrier.
  23. * 85May27 HAW  Code for networking time out.
  24. * 85May06 HAW  Code for daily timeout.
  25. * 85Mar07 HAW  Stick in Sperry PC mods for MSDOS.
  26. * 85Feb22 HAW  Upload/download implemented.
  27. * 85Feb20 HAW  IMPERVIOUS flag implemented.
  28. * 85Feb17 HAW  Baud change functions installed.
  29. * 85Feb09 HAW and Sr.  Chat bug analyzed by Sr.
  30. * 85Jan16 JLS  fastIn modified for CR being first character from modem.
  31. * 85Jan04 HAW  Code added but not tested for new WC functions.
  32. * 84Sep12 HAW  Continue massacre of portability -- bye, pMIReady.
  33. * 84Aug30 HAW  Wheeee!!  MS-DOS time!!
  34. * 84Aug22 HAW  Compilation directive for 8085 chips inserted.
  35. * 84Jul08 JLS & HAW ReadFile() fixed for the 255 rollover.
  36. * 84Jul03 JLS & HAW All references to putCh changed to putChar.
  37. * 84Jun23 HAW & JLS Local unused variables zapped.
  38. * 84Mar07 HAW  Upgrade to BDS 1.50a begun.
  39. * 83Mar01 CrT  FastIn() ignores LFs etc -- CRLF folks won't be trapped.
  40. * 83Feb25 CrT  Possible fix for backspace-in-message-entry problem.
  41. * 83Feb18 CrT  fastIn() upload mode cutting in on people.  Fixed.
  42. * 82Dec16 dvm  modemInit revised for FDC-1, with kludge for use with
  43. *   Big Board development system
  44. * 82Dec06 CrT  2.00 release.
  45. * 82Nov15 CrT  readfile() & sendfile() borrowed from TelEdit.c
  46. * 82Nov05 CrT  Individual history file established
  47. */
  48. #include "ctdl.h"
  49. void DumpToFile(int LastReceived, int BufSize, CRC_TYPE tc, CRC_TYPE oc);
  50. /*
  51. *       Contents
  52. *
  53. * BBSCharReady()    returns true if user input is ready
  54. * ClearWX()   finishes a WXMODEM transmission
  55. * CommonPacket()    reads a block
  56. * CommonWrite()   writes a block to wherever
  57. * FlowControl()   flow control handler for WXMODEM
  58. * GenTrInit()   general init for individual protocols
  59. * getMod()    bottom-level modem-input filter
  60. * iChar()     top-level user-input function
  61. * initTransfers()   initial data buffers of protocols
  62. * interact()    chat mode
  63. * JumpStart()   gets protocol reception going
  64. * MIReady()   check MS-DOS interrupt for data
  65. * modIn()     returns a user char
  66. * modemInit()   top-level initialize-all-modem-stuff
  67. * oChar()     top-level user-output function
  68. * Reception()   receive data via protocol
  69. * recWX()     receive data via WXMODEM
  70. * recWXchar()   receive a WXMODEM char, stripped of DLE
  71. * recXYmodem()    receive data via X or Y MODEM
  72. * ringSysop()   signal chat-mode request
  73. * SendCmnBlk()    sends a WX/X/Y/MODEM block
  74. * sendWCChar()    send file with WC-protocol handshaking
  75. * sendWXchar()    send a char for WXMODEM
  76. * sendWXModem()   send data with WXMODEM protocol
  77. * sendYMChar()    send file with YMODEM protocol
  78. * SummonSysop()   rings bell for ^T
  79. * SurreptitiousChar() process a console character in MODEM
  80. * Transmission()    handles protocol transmission
  81. * WXResponses()   handles NAK/ACK XON/XOFF for WXMODEM
  82. * XYBlock()   common routine for X & Y modem
  83. * XYClear()   finished X or Y MODEM transmission
  84. * YMHdr()     YMODEM BATCH header handler
  85. */
  86. void ReActivate_Window(void);  /* allow window to be activated */
  87. char justLostCarrier = FALSE;   /* Modem <==> rooms connection  */
  88. char newCarrier = FALSE;   /* Just got carrier  */
  89. char onConsole;     /* Who's in control?!?  */
  90. int  outPut = NORMAL;
  91. char modStat;     /* Whether modem had carrier LAST time  */
  92. /* you checked. */
  93. char CallSysop = FALSE;   /* Call sysop on user logout  */
  94. char whichIO = CONSOLE;   /* CONSOLE or MODEM */
  95. #ifdef NEED_VISIBLE
  96. char visibleMode;   /* make non-printables visible? */
  97. #endif
  98. static char captureOn = FALSE;
  99. static FILE *cptFile;
  100. char haveCarrier;   /* set if DCD == TRUE */
  101. char textDownload = FALSE;  /* read host files, TRUE => ASCII */
  102. char echo;      /* Either NEITHER, CALLER, or BOTH  */
  103. char echoChar;      /* What to echo with if echo == NEITHER */
  104. int  TransProtocol;   /* Transfer protocol value  */
  105. int  upDay;     /* Day system was brought up  */
  106. char nextDay;     /* Come down tomorrow rather than today?*/
  107. int  timeCrash;
  108. char anyEcho = TRUE;
  109. char warned;
  110. long netBytes;
  111. char ChatMode;
  112. char NoConsoleBanner;   /* defaults to FALSE */
  113. long TempBytes;
  114. char ConOnly = FALSE;
  115. static char PB = 0;
  116. /* Block transfer variables */
  117. TransferBlock Twindow[4];
  118. #define blk Twindow[0]
  119. int  CurWindow,   /* For sequence #, init to 1 */
  120. TrBlock,    /* For block #, init to 1 */
  121. StartWindow,  /* First block of current Twindow, init = 1 */
  122. TrCount,    /* Byte accumulator counter, init to 0 */
  123. LastSent,   /* Last seq block sent to receiver, regardless of ACK */
  124. CurYBufSize,  /* Size of current YMODEM block to send */
  125. GlobalHeader; /* Starting char of transfer (YMODEM) */
  126. char DoCRC,   /* True if doing CRC */
  127. DLinkError, /* For conveying errors during WXMODEM */
  128. TrError,    /* True only on fatal error */
  129. DLEsignal;    /* True only when an WXMODEM read involved a DLE */
  130. AN_UNSIGNED *DataBuf;
  131. int      TrCksm;  /* Checksum variable for transmissions */
  132. static char *msg[] =
  133.   {
  134.   "NO ERROR",
  135.   "BAD DLE",
  136.   "EARLY SYN",
  137.   "DATA TIMEOUT",
  138.   "BAD CRC",
  139.   "BAD CHECKSUM",
  140.   "BAD SECTOR COMPLEMENT",
  141.   "SYNCH ERROR",
  142.   "WRITE ERROR",
  143.   "CARRIER LOSS"
  144.  
  145.   };
  146. #define WindowFull()    IsSent(0) && IsSent(1) && IsSent(2) && IsSent(3)
  147. #define WindowEmpty()   IsDone(0) && IsDone(1) && IsDone(2) && IsDone(3)
  148. #define IsDone(x) (IsAcked(x) || NotUsed(x))
  149. #define IsSent(x) (Twindow[x].status == SENT)
  150. #define IsAcked(x)  (Twindow[x].status == ACKED)
  151. #define NotUsed(x)  (Twindow[x].status == NOT_USED)
  152. /*
  153. * This table presupposes that XMODEM is defined as 1, YMODEM as 2, WXMODEM
  154. * as 3.  Used only by CommonPacket().
  155. */
  156. static int time_table[] =
  157.   {
  158.   0, 1, 4, 15
  159.  
  160.   };
  161. long ByteCount;
  162. extern MessageBuffer   msgBuf;  /* Message buffer */
  163. extern CONFIG    cfg;   /* Configuration variables  */
  164. extern logBuffer logBuf;  /* Log buffer of a person */
  165. extern aRoom  roomBuf;  /* Room buffer  */
  166. extern FILE *upfd;
  167. extern char loggedIn; /* Is we logged in? */
  168. extern char prevChar; /* previous char  */
  169. extern char outFlag;  /* output flag  */
  170. extern char ExitToMsdos;  /* Kill program flag  */
  171. extern int  exitValue;
  172. /* net stuff vars should go here */
  173. extern char inNet;
  174. extern FILE *netLog;
  175. extern FILE *strollfd;
  176. /* bloooooop! */
  177. extern char netDebug;
  178. extern PROTO_TABLE  Table[];
  179. /*
  180. * BBSCharReady()
  181. *
  182. * This returns TRUE if char is available from user.
  183. * NB: user may be on modem, or may be sysop in CONSOLE mode.
  184. */
  185. char BBSCharReady()
  186.   {
  187.   return (char) (PB || ((haveCarrier && whichIO == MODEM) && MIReady()) ||
  188.   (whichIO == CONSOLE  &&   KBReady()));
  189.  
  190.   }
  191. #ifdef WXMODEM_AVAILABLE
  192. /*
  193. * ClearWX()
  194. *
  195. * This finishes a WXMODEM transmission.
  196. */
  197. int ClearWX()
  198.   {
  199.   int rover, BlockRover, TempSent, SendEOT;
  200.   if (!gotCarrier())
  201.   return CARR_LOSS;
  202.   outMod(EOT);  /* Forces us to wait until output buffer is flushed */
  203.   while (!WindowEmpty())
  204.     {
  205.     WXResponses();
  206.     for (BlockRover = (LastSent + 1) % 4, TempSent = LastSent, SendEOT=0;
  207.     BlockRover != LastSent; BlockRover = (BlockRover + 1) % 4)
  208.       {
  209.       if (Twindow[BlockRover].status != SECTOR_READY) break;
  210.       SendEOT++;
  211.       SendCmnBlk(WXMDM, Twindow + BlockRover, sendWXchar, SECTSIZE);
  212.       Twindow[BlockRover].status = SENT;
  213.       TempSent = BlockRover;
  214.  
  215.       }
  216.     LastSent = TempSent;
  217.     if (!gotCarrier())
  218.     return CARR_LOSS;
  219.     if (SendEOT) outMod(EOT);
  220.  
  221.     }
  222.   for (rover = 1; rover < MAX_WX_ERRORS; rover++)
  223.     {
  224.     if (!gotCarrier())
  225.     return CARR_LOSS;
  226.     if (receive(3) != ACK) outMod(EOT);
  227.     else return TRAN_SUCCESS;
  228.  
  229.     }
  230.   return TRAN_FAILURE;
  231.  
  232.   }
  233. #endif
  234. /*
  235. * CommonPacket()
  236. *
  237. * This reads a block of data (XMDM, YMDM, WXMDM).
  238. */
  239. int CommonPacket(char type, int size, int (*recFn)(int t), int *Sector)
  240.   {
  241.   int  comp, cksm, i, c, hi, lo, time;
  242.   CRC_TYPE crc;
  243.   #ifdef NEED_NET_DEBUG_ERRORS
  244.   CRC_TYPE oc;
  245.   #endif
  246.   /*
  247.   * Format:
  248.   *
  249.   * <SOH | STX><Sec#><w Sec#><size bytes of data><checksum or CRC>
  250.   *
  251.   * SOH | STX has already been received by the caller.  type is used for
  252.   * protocol specific problems, as follows.
  253.   *
  254.   * WXMDM:
  255.   * 1. When SYN is detected without DLEsignal == TRUE, this indicates a bad
  256.   *    packet problem, so that must be checked.
  257.   */
  258.   time = time_table[type];
  259.   *Sector = (*recFn)(time);   /* Get Sector # */
  260.   #ifdef WXMODEM_AVAILABLE
  261.   if (type == WXMDM && *Sector == SYN && !DLEsignal) return EARLY_SYN;
  262.   #endif
  263.   comp = (*recFn)(time);  /* Get Sector #'s complement */
  264.   #ifdef WXMODEM_AVAILABLE
  265.   if (type == WXMDM && comp == SYN && !DLEsignal) return EARLY_SYN;
  266.   #endif
  267.   for (i = cksm = 0; i < size; i++)
  268.     {
  269.     /* Get data block */
  270.     if ((c = (*recFn)(time)) == ERROR)
  271.       {
  272.       if (!gotCarrier())
  273.       return CARR_LOSS;
  274.       if (cfg.BoolFlags.debug)splitF(netLog, "TIMEOUT on byte %d\n", i);
  275.       return DATA_TIMEOUT;
  276.  
  277.       }
  278.     #ifdef WXMODEM_AVAILABLE
  279.     if (  type == WXMDM &&
  280.     c == SYN && !DLEsignal  )
  281.       {
  282.       return EARLY_SYN;
  283.  
  284.       }
  285.     #endif
  286.     DataBuf[i] = c;
  287.     cksm = (c + cksm) & 0xFF;
  288.     if (!gotCarrier()) return CARR_LOSS;
  289.  
  290.     }
  291.   hi = (*recFn)(time);  /* Get cksm or hi byte of CRC */
  292.   if (DoCRC)
  293.     {
  294.     lo = (*recFn)(time);    /* Get lo byte of CRC */
  295.     crc = (hi << 8) + lo;
  296.     if (*Sector + comp == 0xff) /* Validations... */
  297.     if (crc != calcrc(DataBuf, size))
  298.       {
  299.       #ifdef NEED_NET_DEBUG_ERRORS
  300.       splitF(netLog, "CRC error: we calc %x, they sent %x\n", oc=calcrc(DataBuf, size), crc);
  301.       DumpToFile(*Sector, size, crc, oc);
  302.       #endif
  303.       return BAD_CRC;
  304.  
  305.       }
  306.  
  307.     }
  308.   else
  309.     {
  310.     if (hi != cksm)
  311.     return BAD_CKSM;
  312.  
  313.     }
  314.   if (*Sector + comp != 0xFF)
  315.     {
  316.     /* Check this to make sure, too */
  317.     #ifdef NEED_NET_DEBUG_ERRORS
  318.     if (inNet != NON_NET && netDebug)
  319.     splitF(netLog, "BT: %x %x\n", *Sector, comp);
  320.     printf("\nBT: %x %x\n", *Sector, comp);
  321.     #endif
  322.     return BAD_SEC_COMP;
  323.  
  324.     }
  325.   return NO_ERROR;
  326.  
  327.   }
  328. /*
  329. * CommonWrite()
  330. *
  331. * This function writes a block of data to wherever.
  332. */
  333. int CommonWrite(int (*WriteFn)(int c), int size)
  334.   {
  335.   int i;
  336.   for (i = 0; i < size; i++)
  337.   if ((*WriteFn)(DataBuf[i]) == ERROR)
  338.   return WRITE_ERROR;
  339.   return NO_ERROR;
  340.  
  341.   }
  342. #ifdef WXMODEM_AVAILABLE
  343. /*
  344. * FlowControl()
  345. *
  346. * This function handles XON/XOFF for WXMODEM.
  347. */
  348. void FlowControl()
  349.   {
  350.   int val;
  351.   startTimer(WORK_TIMER);
  352.   do
  353.   val = receive(1); /* Use receive in this instance */
  354.   while (val != XON && chkTimeSince(WORK_TIMER) < 10);
  355.  
  356.   }
  357. #endif
  358. /*
  359. * GenTrInit()
  360. *
  361. * General protocol initializations.
  362. */
  363. void GenTrInit()
  364.   {
  365.   int i;
  366.   for (i = 0; i < 4; i++) Twindow[i].status = NOT_USED;
  367.   CurWindow  = TrBlock   = StartWindow = 1;
  368.   TrCount    = LastSent  = TrCksm = 0;
  369.   DLinkError = DLEsignal = FALSE;
  370.   TrError    = TRAN_SUCCESS;
  371.   DoCRC = TRUE;
  372.  
  373.   }
  374. /*
  375. * iChar()
  376. *
  377. * This is the top-level user-input function -- this is the function the rest
  378. * of Citadel uses to obtain user input.
  379. */
  380. char iChar()
  381.   {
  382.   char  c;
  383.   extern AN_UNSIGNED crtColumn; /* current position on screen */
  384.   if (justLostCarrier)   return 0;    /* ugly patch   */
  385.   c = cfg.filter[modIn() & 0x7f];
  386.   switch (echo)
  387.     {
  388.     case BOTH:
  389.     if (haveCarrier)
  390.       {
  391.       if (c == '\n')
  392.         {
  393.         if (!HalfDup) doCR();
  394.  
  395.         }
  396.       else
  397.       if (!HalfDup) outMod(c);
  398.  
  399.       }
  400.     mputChar(c);  /* Let putChar decide if it should go on console */
  401.     crtColumn += (c == '\b') ? -1 : 1;
  402.     break;
  403.     case CALLER:
  404.     if (whichIO == MODEM)
  405.       {
  406.       if (c == '\n')
  407.         {
  408.         if (!HalfDup) doCR();
  409.  
  410.         }
  411.       else
  412.         {
  413.         if (!HalfDup) outMod(c);
  414.  
  415.         }
  416.  
  417.       }
  418.     else
  419.       {
  420.       mputChar(c);
  421.  
  422.       }
  423.     crtColumn += (c == '\b') ? -1 : 1;
  424.     break;
  425.     case NEITHER:
  426.     if (echoChar != '\0')
  427.       {
  428.       if (whichIO == MODEM)
  429.         {
  430.         if (c == '\n') doCR();
  431.         else if (c <= ' ') outMod(c);
  432.         else  outMod(echoChar);
  433.  
  434.         }
  435.       else
  436.         {
  437.         if (c == '\n') doCR();
  438.         else if (c <= ' ') mputChar(c);
  439.         else  mputChar(echoChar);
  440.  
  441.         }
  442.       crtColumn += (c == '\b') ? -1 : 1;
  443.  
  444.       }
  445.     break;
  446.  
  447.     }
  448.   return(c);
  449.  
  450.   }
  451. /*
  452. * initTransfers()
  453. *
  454. * This initializes data buffers for protocol transfers.
  455. */
  456. void initTransfers()
  457.   {
  458.   int i;
  459.   for (i = 1; i < 4; i++)
  460.     {
  461.     Twindow[i].buf = GetDynamic(SECTSIZE);
  462.  
  463.     }
  464.   DataBuf = blk.buf = GetDynamic(YM_BLOCK_SIZE);
  465.  
  466.   }
  467. /*
  468. * interact()
  469. *
  470. * Here we try to chat with the users.  Or at least the modem.
  471. */
  472. void interact(char ask)
  473.   {
  474.   char CallerDumb;
  475.   char last = 0;
  476.   int  c = 0;
  477.   extern char *APPEND_TEXT;
  478.   ChatMode = TRUE;
  479.   printf("\nDirect modem-interaction mode\n");
  480.   if (ask)
  481.     {
  482.     ConOnly = TRUE;
  483.     CallerDumb = getYesNo("DUMBCL");
  484.     ConOnly = FALSE;
  485.     if (!gotCarrier()) EnableModem(FALSE);
  486.  
  487.     }
  488.   else
  489.     {
  490.     CallerDumb = FALSE;
  491.  
  492.     }
  493.   printf("<ESC> to exit\n");
  494.   /* incredibly ugly code.  Rethink sometime: */
  495.   while (c != SPECIAL )
  496.     {
  497.     c = 0;
  498.     BufferingOn();
  499.     if (MIReady())
  500.       {
  501.       c = inp() & 0x7f;
  502.       if( c == '\0')c = SPECIAL;
  503.       if (c == SPECIAL && !ask) c = 0;
  504.       if (c != '\r') c = cfg.filter[c];
  505.       if (c != '\r')
  506.         {
  507.         if (CallerDumb && c != ESC && c != 0)   outMod(c);
  508.         if (c != 0) interOut(c);
  509.  
  510.         }
  511.       else
  512.         {
  513.         interOut('\n');
  514.         if (CallerDumb)
  515.           {
  516.           outMod('\r');
  517.           outMod('\n');
  518.  
  519.           }
  520.  
  521.         }
  522.  
  523.       }
  524.     else if (KBReady())
  525.       {
  526.       BufferingOff();
  527.       if ((c = getCh()) == '\r') c = '\n';
  528.       if (c == CPT_SIGNAL)
  529.         {
  530.         /* capture input? */
  531.         captureOn = !captureOn;
  532.         if (captureOn)
  533.           {
  534.           if ((cptFile = safeopen("chat.txt", APPEND_TEXT)) == NULL)
  535.             {
  536.             printf("\nCOULDN'T OPEN/APPEND TO CHAT.TXT!\n");
  537.             captureOn = FALSE;
  538.  
  539.             }
  540.           else
  541.             {
  542.             printf("\nAppending to CHAT.TXT\n");
  543.             mPrintf(
  544.             "\n WARNING from Citadel: This chat is now being recorded.\n ");
  545.  
  546.             }
  547.  
  548.           }
  549.         else
  550.           {
  551.           fclose(cptFile);
  552.           printf("\nCapture finished\n");
  553.           mPrintf(
  554.           " \nMessage from Citadel: Chat no longer being captured.\n ");
  555.  
  556.           }
  557.  
  558.         }
  559.       else if (c == 5 || ChatEat(c))
  560.         {
  561.         ChatGrab(TRUE);
  562.  
  563.         }
  564.       else if (c == 6 || ChatSend(c))
  565.         {
  566.         ChatGrab(FALSE);
  567.  
  568.         }
  569.       else if (c != NEWLINE)
  570.         {
  571.         if (CallerDumb)  interOut(c);
  572.         if (c != ESC && c != '\\')   outMod(c);
  573.         else
  574.           {
  575.           if (last == '\\')
  576.             {
  577.             outMod(c);
  578.             c = 0;
  579.  
  580.             }
  581.  
  582.           }
  583.         last = c;
  584.  
  585.         }
  586.       else
  587.         {
  588.         outMod('\r');
  589.         if (CallerDumb)
  590.           {
  591.           interOut('\n');
  592.           outMod('\n');
  593.  
  594.           }
  595.  
  596.         }
  597.  
  598.       }
  599.     else
  600.       {
  601.       BufferingOff();
  602.       BeNice(CHAT_NICE);
  603.       DoTimeouts();
  604.  
  605.       }
  606.  
  607.     }
  608.   if (captureOn)
  609.     {
  610.     captureOn = FALSE;
  611.     fclose(cptFile);
  612.  
  613.     }
  614.   if (!gotCarrier() && whichIO == CONSOLE)
  615.   DisableModem(FALSE);
  616.   ChatMode = FALSE;
  617.   BufferingOff();
  618.  
  619.   }
  620. /*
  621. * ChatGrab()
  622. *
  623. * This function implements downloading from Chat.
  624. */
  625. void ChatGrab(char Up)
  626.   {
  627.   SListBase CSelects =
  628.     {
  629.     NULL, FindSelect, NULL, NoFree, NULL
  630.  
  631.     };
  632.   char *Protocols[] =
  633.     {
  634.     TERM "Xmodem",
  635.     #ifdef WXMODEM_AVAILABLE
  636.     TERM "Wxmodem",
  637.     #endif
  638.     TERM "Ymodem",
  639.     /* these are the external protocols */
  640.     " ", " ", " ", " ", " ",
  641.     " ", " ", " ", " ", " ",
  642.     " ", " ", " ", " ", " ",
  643.     ""
  644.  
  645.     };
  646.   char  letter[2];
  647.   int   protocol;
  648.   label roomName;
  649.   if (roomBuf.rbflags.ISDIR != 1)
  650.     {
  651.     printf("\nSorry this is not a directory room.\nNew room? ");
  652.     ConOnly = TRUE;
  653.     getNormStr("", roomName, NAMESIZE, 0);
  654.     ConOnly = FALSE;
  655.     if (strLen(roomName) == 0) return;
  656.     gotoRoom(roomName, 'R');
  657.     if (roomBuf.rbflags.ISDIR != 1)
  658.       {
  659.       printf("\nNor is this is a directory room.\n");
  660.       return;
  661.  
  662.       }
  663.  
  664.     }
  665.   printf((Up) ? "Grabbing file from other system (into %s)\n" :
  666.   "Sending file to other system (from %s)\n", roomBuf.rbname);
  667.   ConOnly = TRUE;
  668.   AddExternProtocolOptions(Protocols, Up);
  669.   printf("\nProtocol: ");
  670.   CmdMenuList(Protocols, &CSelects, NULL, letter, FALSE, FALSE);
  671.   switch (letter[0])
  672.     {
  673.     #ifdef WXMODEM_AVAILABLE
  674.     case 'X':
  675.     case 'W':
  676.     case 'Y':
  677.     protocol    = (letter[0] == 'W') ? WXMDM :
  678.     (letter[0] == 'X') ? XMDM : YMDM;
  679.     break;
  680.     #else
  681.     case 'X':
  682.     case 'Y':
  683.     protocol    = (letter[0] == 'X') ? XMDM : YMDM;
  684.     break;
  685.     #endif
  686.     default:
  687.     if ((protocol = FindProtocolCode(letter[0], Up)) == -1)
  688.       {
  689.       ConOnly = FALSE;
  690.       /* KillList(&CSelects); */
  691.       return ;
  692.  
  693.       }
  694.  
  695.     }
  696.   if (Up) upLoad(protocol,NULL,FALSE);
  697.   else    TranFiles(protocol, "");
  698.   ConOnly = FALSE;
  699.   /* KillList(&CSelects); */
  700.   printf("\nBack in Chat.\n");
  701.  
  702.   }
  703. /*
  704. * interOut()
  705. *
  706. * This function actually implements chat capture and general interact()
  707. * output.
  708. */
  709. void interOut(char c)
  710.   {
  711.   mputChar(c);
  712.   if (captureOn)
  713.   fputc(c, cptFile);
  714.  
  715.   }
  716. /*
  717. * JumpStart()
  718. *
  719. * Generic jump start for Reception.
  720. */
  721. char JumpStart(int tries, int timeout, int Starter, int t1, int t2,
  722. char (*Method)(int (*wrt)(int c)), int (*WriteFn)(int c))
  723.   {
  724.   int StartTries;
  725.   for (StartTries = 0; StartTries < tries; StartTries++)
  726.     {
  727.     if (!gotCarrier())
  728.       {
  729.       #ifdef NEED_NET_DEBUG_ERRORS
  730.       if (inNet != NON_NET)
  731.       splitF(netLog, "RecError: JS Carr Loss\n");
  732.       #endif
  733.       return CARR_LOSS;
  734.  
  735.       }
  736.     outMod(Starter);
  737.     GlobalHeader = receive(timeout);
  738.     if (GlobalHeader == t1 || GlobalHeader == t2)
  739.       {
  740.       return (*Method)(WriteFn);
  741.  
  742.       }
  743.     if (GlobalHeader == CAN)
  744.       {
  745.       #ifdef NEED_NET_DEBUG_ERRORS
  746.       if (inNet != NON_NET)
  747.       splitF(netLog, "RecError: JS JS received CAN\n");
  748.       #endif
  749.       return CANCEL;
  750.  
  751.       }
  752.     if (GlobalHeader == EOT)
  753.       {
  754.       outMod(ACK);
  755.       return TRAN_SUCCESS;  /* zero length data */
  756.  
  757.       }
  758.  
  759.     }
  760.   return NO_LUCK;
  761.  
  762.   }
  763. /*
  764. * ModemSetup()
  765. *
  766. * This function will set up modem handling variables.
  767. */
  768. char ModemSetup(char ShouldBeCarrier)
  769.   {
  770.   haveCarrier = modStat = gotCarrier();
  771.   if (ShouldBeCarrier && !haveCarrier) return FALSE;
  772.   if (!ShouldBeCarrier && haveCarrier)
  773.     {
  774.     HangUp(TRUE);
  775.     haveCarrier = modStat = gotCarrier();
  776.  
  777.     }
  778.   return TRUE;
  779.  
  780.   }
  781. /**
  782. * modIn()
  783. *
  784. * toplevel modem-input function.
  785. *
  786. * If DCD status has changed since the last access, reports carrier present or
  787. * absent and sets flags as appropriate.  In case of a carrier loss, waits 20
  788. * ticks and rechecks carrier to make sure it was not a temporary glitch.
  789. * If carrier is newly received, returns newCarrier = TRUE;  if carrier lost
  790. * returns 0.  If carrier is present and state has not changed, gets a
  791. * character if present and returns it.  If a character is typed at the console,
  792. * checks to see if it is keyboard interrupt character.  If so, prints
  793. * short-form console menu and awaits next keyboard character.
  794. *
  795. * Globals modified:    carrierDetect   modStat    haveCarrier
  796. *     justLostCarrier whichIO   ExitToMsDos
  797. *     visibleMode
  798. * Returns:  modem or console input character,
  799. *   or above special values
  800. **/
  801. #define MAX_TIME  210l  /* Time out is 210 seconds  */
  802. AN_UNSIGNED modIn()
  803.   {
  804.   AN_UNSIGNED logVal = 0;
  805.   AN_UNSIGNED c;
  806.   char *whatRate;
  807.   char signal = FALSE;
  808.   if (PB)
  809.     {
  810.     c = PB;
  811.     PB = 0;
  812.     return c;
  813.  
  814.     }
  815.   if (!onLine() && CallSysop)SummonSysop();
  816.   startTimer(WORK_TIMER);
  817.   while (TRUE)
  818.     {
  819.     if ((whichIO==MODEM) && (c=gotCarrier()) != modStat)
  820.       {
  821.       /* carrier changed   */
  822.       if (c)
  823.         {
  824.         /* carrier present   */
  825.         if (Find_baud(&whatRate))
  826.           {
  827.           printf("Carr-detect (%s)\n", whatRate);
  828.           warned      = FALSE;
  829.           haveCarrier = TRUE;
  830.           modStat     = c;
  831.           newCarrier  = TRUE;
  832.           justLostCarrier = FALSE;
  833.           logMessage(BAUD, whatRate, FALSE);
  834.           ScrNewUser();
  835.  
  836.           }
  837.         else
  838.         HangUp(TRUE);
  839.         return(0);
  840.  
  841.         }
  842.       else
  843.         {
  844.         pause(100);   /* confirm it's not a glitch */
  845.         if (!gotCarrier())
  846.           {
  847.           /* check again */
  848.           printf("Carr-loss\n");
  849.           logMessage(CARRLOSS, "", logVal);
  850.           HangUp(TRUE);
  851.           modStat = haveCarrier = FALSE;
  852.           justLostCarrier = TRUE;
  853.           startTimer(NEXT_ANYNET);  /* start anytime net timer */
  854.           return(0);
  855.  
  856.           }
  857.  
  858.         }
  859.  
  860.       }
  861.     if (MIReady())
  862.       {
  863.       if (haveCarrier)
  864.         {
  865.         c = inp() & 0x7f;
  866.         if (whichIO == MODEM)   return c;
  867.  
  868.         }
  869.  
  870.       }
  871.     if (KBReady())
  872.       {
  873.       c = getCh();
  874.       if (whichIO == CONSOLE) return(c);
  875.       else
  876.         {
  877.         if (!SurreptitiousChar(c))
  878.         return 0;
  879.  
  880.         }
  881.  
  882.       }
  883.     if (DoTimeouts()) return 0;
  884.     /* check for no input.  (Short-circuit evaluation, remember!) */
  885.     if ((whichIO==MODEM  &&  haveCarrier  &&
  886.     chkTimeSince(WORK_TIMER) >= MAX_TIME) ||
  887.     (whichIO == CONSOLE && cfg.ConTimeOut != 0 &&
  888.     chkTimeSince(WORK_TIMER) >= cfg.ConTimeOut))
  889.       {
  890.       mPrintf("Sleeping? Call again :-)");
  891.       logVal = 't';
  892.       if (whichIO == MODEM)
  893.       HangUp(FALSE);
  894.       else
  895.         {
  896.         logMessage(CARRLOSS, "", logVal);
  897.         justLostCarrier = TRUE;
  898.         onConsole = FALSE;
  899.         return 0;
  900.  
  901.         }
  902.  
  903.       }
  904.     else if ((whichIO == MODEM &&
  905.     haveCarrier &&
  906.     chkTimeSince(WORK_TIMER) == MAX_TIME - 10) ||
  907.     (whichIO == CONSOLE && cfg.ConTimeOut != 0 &&
  908.     chkTimeSince(WORK_TIMER) == cfg.ConTimeOut - 10))
  909.       {
  910.       if (!signal)
  911.       oChar(BELL);
  912.       signal = TRUE;
  913.  
  914.       }
  915.     BeNice((haveCarrier || onConsole) ? INUSE_PAUSE : IDLE_PAUSE);
  916.  
  917.     }
  918.  
  919.   }
  920. /*
  921. * SurreptitiousChar()
  922. *
  923. * This function will process a console character when the system is in modem
  924. * mode.
  925. */
  926. int SurreptitiousChar(char c)
  927.   {
  928.   switch (toUpper(c))
  929.     {
  930.     case CON_NEXT:    /* ^T */
  931.     if (onLine())
  932.       {
  933.       CallSysop = !CallSysop;
  934.       printf("\nSysop call toggle is %s\n", CallSysop ? "ON" : "OFF");
  935.       ScrNewUser();
  936.       break;
  937.  
  938.       }
  939.     /* yes, don't break here! */
  940.     case SPECIAL:   /* ESC */
  941.     printf("CONSOLE mode\n ");
  942.     whichIO = CONSOLE;
  943.     if (!gotCarrier())
  944.       {
  945.       DisableModem(FALSE);
  946.       logMessage(BAUD, "", FALSE);
  947.  
  948.       }
  949.     setUp(FALSE);
  950.     if (!gotCarrier())
  951.       {
  952.       ScrNewUser();
  953.       if (!NoConsoleBanner)
  954.       newCarrier = TRUE;
  955.  
  956.       }
  957.     warned = FALSE;
  958.     return FALSE;
  959.     case 1:     /* ^A */
  960.     ForceAnytime();
  961.     break;
  962.     case 5:     /* ^E */
  963.     anyEcho = !anyEcho;
  964.     ScrNewUser();
  965.     break;
  966.     case CNTRLD:
  967.     cfg.BoolFlags.debug  = !cfg.BoolFlags.debug;
  968.     break;
  969.     case CNTRLZ:
  970.     cfg.BoolFlags.noChat = !cfg.BoolFlags.noChat;
  971.     ScrNewUser();
  972.     break;
  973.  
  974.     }
  975.   return TRUE;
  976.  
  977.   }
  978. /*
  979. * oChar()
  980. *
  981. * This function is the top-level user-output routine.  It sends to modem port
  982. * and console, does conversion to upper-case etc as necessary in "debug" mode,
  983. * converts control chars to uppercase letters
  984. * Globals modified: prevChar
  985. */
  986. int delay_factor= -1;
  987. void oChar(char c)
  988.   {
  989.   prevChar = c;     /* for end-of-paragraph code    */
  990.   if (outFlag != OUTOK &&   /* s(kip) mode  */
  991.   outFlag != IMPERVIOUS)
  992.   return;
  993.   if( !onConsole && logBuf.lbdelay > 0 && delay_factor == -1)
  994.     {
  995.     delay_factor = ( 256 - logBuf.lbdelay );
  996.     };
  997.  
  998.   if (c == NEWLINE)   c = ' ';  /* doCR() handles real newlines */
  999.   /* show on console  */
  1000.   if (outPut == DISK)
  1001.   putc(c, upfd);
  1002.   else
  1003.     {
  1004.     if (haveCarrier && !ConOnly)
  1005.     (*Table[TransProtocol].method)(c);
  1006.     if (TransProtocol == ASCII)
  1007.       {
  1008.       mputChar(c);
  1009.       if (!onConsole && logBuf.lbdelay > 0 )
  1010.          {
  1011.          if( delay_factor-- < 1 )
  1012.            {
  1013.            delay_factor = ( 256 - logBuf.lbdelay );
  1014.            MilliSecPause(3);
  1015.            };
  1016.          };
  1017.  
  1018.       }
  1019.  
  1020.     }
  1021.   crtColumn += (c == '\b') ? -1 : 1;
  1022.  
  1023.   }
  1024. /*
  1025. * PushBack()
  1026. */
  1027. void PushBack(char c)
  1028.   {
  1029.   PB = c;
  1030.  
  1031.   }
  1032. /*
  1033. * Reception()
  1034. *
  1035. * This function reads data, trying to use specified protocol.  Note: This only
  1036. * handles XMODEM, WXMODEM, and YMODEM.  Due to the multiple authors of these
  1037. * protocols, this code is a mess.  I do da best I can, wid da leetle brain
  1038. * giben me.
  1039. */
  1040. char Reception(int protocol, int (*WriteFn)(int c))
  1041.   {
  1042.   char RetVal;
  1043.   if (!gotCarrier())
  1044.   return CARR_LOSS;
  1045.   GenTrInit();
  1046.   #ifdef WXMODEM_AVAILABLE
  1047.   /* From P. Boswell's WXMODEM doc */
  1048.   if (protocol == WXMDM)
  1049.     {
  1050.     if ((RetVal = JumpStart(3, 3, 'W', SYN, SYN, recWX, WriteFn))
  1051.     != NO_LUCK)
  1052.     return RetVal;
  1053.     if ((RetVal = JumpStart(3, 3, 'C', SOH, SOH, recXYmodem, WriteFn))
  1054.     != NO_LUCK)
  1055.     return RetVal;
  1056.     DoCRC = FALSE;
  1057.     if ((RetVal = JumpStart(4, 3, NAK, SOH, SOH, recXYmodem, WriteFn))
  1058.     != NO_LUCK)
  1059.     return RetVal;
  1060.  
  1061.     }
  1062.   /* From Ward's XMODEM.DOC -- 10 seconds between start tries */
  1063.   else
  1064.   #endif
  1065.   if (protocol == XMDM)
  1066.     {
  1067.     if ((RetVal = JumpStart((inNet != NON_NET) ? 2 : 4, 10, 'C', SOH,
  1068.     SOH, recXYmodem, WriteFn)) != NO_LUCK)
  1069.     return RetVal;
  1070.     DoCRC = FALSE;
  1071.     if ((RetVal = JumpStart(6, 10, NAK, SOH, SOH, recXYmodem, WriteFn))
  1072.     != NO_LUCK)
  1073.     return RetVal;
  1074.  
  1075.     }
  1076.   /* Extrapolated from C. Forsberg's doc and WC's doc. */
  1077.   else if (protocol == YMDM)
  1078.   if ((RetVal = JumpStart(10, 10, 'C', SOH, STX, recXYmodem, WriteFn))
  1079.   != NO_LUCK)
  1080.   return RetVal;
  1081.   return NO_START;
  1082.  
  1083.   }
  1084. #ifdef WXMODEM_AVAILABLE
  1085. /*
  1086. * recWX()
  1087. *
  1088. * This function receives data via WXMODEM.
  1089. */
  1090. char recWX(int (*WriteFn)(int c))
  1091.   {
  1092.   int CurChar,
  1093.   LastChar, /* Confirm that SOH follows a SYN */
  1094.   lastReceived = 0,
  1095.   Sector,
  1096.   SectorResult,
  1097.   LastError = NO_ERROR,
  1098.   LastNak = -1;
  1099.   /*
  1100.   * Assume that the startup part of the protocol has completed, which would
  1101.   * be indicated by a SYN -- already received by us.
  1102.   */
  1103.   CurChar = SYN;
  1104.   do
  1105.     {
  1106.     DLinkError = NO_ERROR;
  1107.     if (inNet == NON_NET) printf("Awaiting block %d\r", lastReceived +1);
  1108.     /*
  1109.     * Get starting SOH, discarding leading SYN and other characters.
  1110.     */
  1111.     do
  1112.       {
  1113.       LastChar = CurChar;
  1114.       CurChar = recWXchar(15);
  1115.  
  1116.       }
  1117.     while (!(CurChar == SOH && LastChar == SYN) && CurChar != EOT &&
  1118.     gotCarrier());
  1119.     if (CurChar != EOT)
  1120.       {
  1121.       SectorResult = CommonPacket(WXMDM, 128, recWXchar, &Sector);
  1122.       if (SectorResult == NO_ERROR)
  1123.         {
  1124.         if (Sector == (lastReceived + 1) % 256)
  1125.           {
  1126.           SectorResult = CommonWrite(WriteFn, SECTSIZE);
  1127.           lastReceived = Sector;
  1128.  
  1129.           }
  1130.         sendWXchar(ACK);
  1131.         sendWXchar(Sector & 3);
  1132.  
  1133.         }
  1134.       if (SectorResult != NO_ERROR)
  1135.         {
  1136.         /*
  1137.         * See Section 6.4.4 of the WXMODEM doc.
  1138.         */
  1139.         /*      if (!inNet) printf("Error: %s\n", msg[SectorResult]); */
  1140.         #ifdef NEED_NET_DEBUG_ERRORS
  1141.         splitF(netLog, "Error: %s\n", msg[SectorResult]);
  1142.         #endif
  1143.         if (SectorResult == CARR_LOSS)
  1144.           {
  1145.           return TRAN_FAILURE;
  1146.  
  1147.           }
  1148.         if (SectorResult == WRITE_ERROR)
  1149.           {
  1150.           sendWXchar(CAN);    /* Cancel transfer - fatal error */
  1151.           sendWXchar(CAN);
  1152.           sendWXchar(CAN);
  1153.           return TRAN_FAILURE;
  1154.  
  1155.           }
  1156.         if (LastError == NO_ERROR || Sector == LastNak)
  1157.           {
  1158.           sendWXchar(NAK);
  1159.           sendWXchar(Sector & 3);
  1160.           LastError = SectorResult;
  1161.           LastNak = Sector;
  1162.  
  1163.           }
  1164.  
  1165.         }
  1166.       else if (lastReceived == Sector)
  1167.         {
  1168.         LastError = NO_ERROR;   /* Clear signal */
  1169.         LastNak   = -1;
  1170.  
  1171.         }
  1172.  
  1173.       }
  1174.  
  1175.     }
  1176.   while (CurChar != EOT);
  1177.   sendWXchar(ACK);    /* Ack the EOT, indicates end of file */
  1178.   return TRAN_SUCCESS;
  1179.  
  1180.   }
  1181. /*
  1182. * recWXchar()
  1183. *
  1184. * This function reads a character, strips any leading DLE.
  1185. */
  1186. int recWXchar(int ErrorTime)
  1187.   {
  1188.   int result;
  1189.   if ((result = receive(ErrorTime)) == ERROR)
  1190.   return ERROR;
  1191.   if (result == DLE)
  1192.     {
  1193.     DLEsignal = TRUE;
  1194.     if ((result = receive(ErrorTime)) == ERROR)
  1195.     return ERROR;
  1196.     result ^= 64;
  1197.     switch (result)
  1198.       {
  1199.       case DLE:
  1200.       case SYN:
  1201.       case XON:
  1202.       case XOFF: break;
  1203.       default:
  1204.       DLinkError = BAD_DLE;
  1205.       result  = ERROR;
  1206.       break;
  1207.  
  1208.       }
  1209.  
  1210.     }
  1211.   else DLEsignal = FALSE;
  1212.   return result;
  1213.  
  1214.   }
  1215. #endif
  1216. /*
  1217. * recXYmodem()
  1218. *
  1219. * This function receives data via YMODEM SINGLE.
  1220. *      (May also work with XMODEM...)
  1221. * Note: algorithm modified to ACK the transmitter before trying
  1222. * to write to disk (or wherever).  This should up performance, but
  1223. * at the expense code complexity.
  1224. */
  1225. char recXYmodem(int (*WriteFn)(int c))  /* Supports YMODEM SINGLE mode only */
  1226.   {
  1227.   char AbortTransmission = FALSE, WriteError = FALSE;
  1228.   int  SectorResult,    /* Result of packet read */
  1229.   Sector,   /* Sector # received */
  1230.   LastReceived = 0, /* Last sector received */
  1231.   TotalErrors = 0,  /* Total errors for this transmission */
  1232.   CurrentErrors = 0,  /* Total errors for block */
  1233.   SOH_val,    /* SOH indicates 128, STX 1024 */
  1234.   BufSize;    /* In conjunction with SOH_val */
  1235.   /*
  1236.   * Assume that the initial SOH or STX has been received.  An initial EOT
  1237.   * should also be handled by the startup function.
  1238.   */
  1239.   SOH_val = GlobalHeader; /* Set by startup function, is global */
  1240.   do
  1241.     {
  1242.     BufSize = (SOH_val == SOH) ? SECTSIZE : YM_BLOCK_SIZE;
  1243.     SectorResult = CommonPacket(YMDM, BufSize, receive, &Sector);
  1244.     if (WriteError) SectorResult = WRITE_ERROR;
  1245.     if (SectorResult == NO_ERROR)
  1246.       {
  1247.       if ((Sector == (LastReceived + 1) % 256) ||
  1248.       Sector == LastReceived)
  1249.       outMod(ACK);
  1250.       if (Sector == (LastReceived + 1) % 256)
  1251.         {
  1252.         WriteError = (CommonWrite(WriteFn, BufSize) == WRITE_ERROR);
  1253.         LastReceived++;
  1254.         if (inNet == NON_NET)
  1255.         printf("Block %d received (try %d, %d total errors)\r",
  1256.         LastReceived,
  1257.         CurrentErrors,
  1258.         TotalErrors);
  1259.  
  1260.         }
  1261.       else if (Sector != LastReceived)
  1262.       SectorResult = SYNCH_ERROR;
  1263.  
  1264.       }
  1265.     if (SectorResult != NO_ERROR)
  1266.       {
  1267.       TotalErrors++;
  1268.       splitF(netLog, "Error on sector %d: %s (%d)\n", LastReceived+1,msg[SectorResult],CurrentErrors+1);
  1269.       switch (SectorResult)
  1270.         {
  1271.         case SYNCH_ERROR:
  1272.         case WRITE_ERROR:
  1273.         outMod(CAN);
  1274.         outMod(CAN);
  1275.         outMod(CAN);    /* Fatal error -- cancel transmission */
  1276.         case CARR_LOSS: /* Don't bother with CANs here */
  1277.         AbortTransmission = TRUE;
  1278.         splitF(netLog, "\nAborting reception due to %s error\n",
  1279.         msg[SectorResult]);
  1280.         break;
  1281.         default:  /* Some normal problem */
  1282.         outMod(NAK);
  1283.         if (CurrentErrors++ >= 9)
  1284.           {
  1285.           AbortTransmission = TRUE;
  1286.           splitF(netLog,
  1287.           "Aborting reception due to 10 consecutive errors\n");
  1288.  
  1289.           }
  1290.  
  1291.         }
  1292.  
  1293.       }
  1294.     else
  1295.       {
  1296.       CurrentErrors = 0;
  1297.  
  1298.       }
  1299.     if (!AbortTransmission)
  1300.       {
  1301.       do
  1302.       SOH_val = receive(10);
  1303.       while (SOH_val != EOT && SOH_val != SOH && SOH_val != CAN &&
  1304.       SOH_val != STX && gotCarrier());
  1305.  
  1306.       }
  1307.  
  1308.     }
  1309.   while (SOH_val != EOT && !AbortTransmission && SOH_val != CAN);
  1310.   if (AbortTransmission)
  1311.   splitF(netLog, "Leaving recXY loop due to AT\n");
  1312.   if (!AbortTransmission && SOH_val != CAN )
  1313.     {
  1314.     outMod(ACK);    /* Ack the EOT, indicates end of file */
  1315.     return TRAN_SUCCESS;
  1316.  
  1317.     }
  1318.   else return TRAN_FAILURE;
  1319.  
  1320.   }
  1321. /*
  1322. * ringSysop()
  1323. *
  1324. * This function signals a chat mode request.  Exits on input from modem or
  1325. * keyboard.
  1326. */
  1327. #define RING_LIMIT 6
  1328. void ReActivate_Window(void);
  1329. void ringSysop()
  1330.   {
  1331.   char answered;
  1332.   int  i, ring;
  1333.   ReActivate_Window();
  1334.   mPrintf("\n Ringing sysop.\n ");
  1335.   answered = FALSE;
  1336.   for (ring = 0; ring < RING_LIMIT && !answered && gotCarrier(); ring++)
  1337.     {
  1338.     for (i=0; !BBSCharReady() && !KBReady(); i = ++i % 7)
  1339.       {
  1340.       /* play shave-and-a-haircut/two bits... as best we can: */
  1341.       oChar(BELL);
  1342.       pause(cfg.shave[i]);
  1343.       if (i == 6) ring++;
  1344.  
  1345.       }
  1346.     if (BBSCharReady() || KBReady()) answered = TRUE;
  1347.  
  1348.     }
  1349.   if (KBReady())
  1350.     {
  1351.     getCh();
  1352.     whichIO = CONSOLE;
  1353.     interact(TRUE);
  1354.     whichIO = MODEM;
  1355.  
  1356.     }
  1357.   else if (ring >= RING_LIMIT)
  1358.     {
  1359.     cfg.BoolFlags.noChat = TRUE;
  1360.     mPrintf("\n Sorry, Sysop not around...\n ");
  1361.  
  1362.     }
  1363.   else modIn();
  1364.  
  1365.   }
  1366. /*
  1367. * SendCmnBlk()
  1368. *
  1369. * This function sends a WX/X/Y Modem block.
  1370. */
  1371. void SendCmnBlk(char type, TransferBlock *block,char (*SendFn)(int c), int size)
  1372.   {
  1373.   int rover;
  1374.   #ifndef NEED_NET_DEBUG_ERRORS
  1375.   if (inNet == NON_NET)
  1376.   printf("Sending block %d\r", block->ThisBlock);
  1377.   #else
  1378.   splitF(netLog, "Sending block %d, type %d, size %d\n", block->ThisBlock, type, size);
  1379.   #endif
  1380.   #ifdef WXMODEM_AVAILABLE
  1381.   if (type == WXMDM)
  1382.     {
  1383.     /* Thrust out some SYNs first */
  1384.     fastMod(SYN);
  1385.     fastMod(SYN);
  1386.  
  1387.     }
  1388.   else
  1389.   #endif
  1390.   BufferingOn();
  1391.   (*SendFn)((size == SECTSIZE) ? SOH : STX);
  1392.   (*SendFn)(block->ThisBlock & 0xFF);
  1393.   (*SendFn)(~(block->ThisBlock & 0xff));
  1394.   for (rover = 0; rover < size; rover++)
  1395.     {
  1396.     (*SendFn)(block->buf[rover]);
  1397.     #ifdef WXMODEM_AVAILABLE
  1398.     if (type == WXMDM) WXResponses();
  1399.     #endif
  1400.     if (!gotCarrier())
  1401.       {
  1402.       TrError = CARR_LOSS;
  1403.       splitF(netLog, "SendCmnBlk lost carrier\n");
  1404.       BufferingOff();
  1405.       return ;
  1406.  
  1407.       }
  1408.  
  1409.     }
  1410.   /*
  1411.   * Handle CRC/Checksum stuff.
  1412.   */
  1413.   if (DoCRC)
  1414.     {
  1415.     (*SendFn)(((block->ThisCRC & 0xff00) >> 8));
  1416.  
  1417.     }
  1418.   (*SendFn)(block->ThisCRC & 0xff);
  1419.   BufferingOff();
  1420.  
  1421.   }
  1422. /*
  1423. * sendWCChar()
  1424. *
  1425. * This function sends a file using Ward Christensen's protocol.
  1426. * (i.e., compatable with xModem, modem7, modem2, YAM, ... )
  1427. */
  1428. int sendWCChar(int c)
  1429.   {
  1430.   if (TrError != TRAN_SUCCESS)
  1431.   return FALSE;
  1432.   blk.buf[TrCount++] = c;
  1433.   TrCksm = (TrCksm + c) & 0xFF;
  1434.   if (TrCount != SECTSIZE)
  1435.   return TRUE;
  1436.   blk.ThisBlock = TrBlock;
  1437.   blk.ThisCRC   = (DoCRC) ? calcrc(blk.buf, SECTSIZE) : TrCksm;
  1438.   return (XYBlock(XMDM, SECTSIZE));
  1439.  
  1440.   }
  1441. #ifdef WXMODEM_AVAILABLE
  1442. /*
  1443. * sendWXchar()
  1444. *
  1445. * This function sends a char via WXMODEM with appropriate leaders, etc.
  1446. */
  1447. char sendWXchar(int data)
  1448.   {
  1449.   data &= 0xff;
  1450.   switch (data)
  1451.     {
  1452.     case DLE:
  1453.     case SYN:
  1454.     case XON:
  1455.     case XOFF:
  1456.     fastMod(DLE);
  1457.     fastMod(data ^ 64);
  1458.     break;
  1459.     default:
  1460.     fastMod(data);
  1461.     break;
  1462.  
  1463.     }
  1464.   return 0;
  1465.  
  1466.   }
  1467. /*
  1468. * sendWXModem()
  1469. *
  1470. * This function sends a character using WXMODEM protocol.
  1471. */
  1472. int sendWXModem(int c)
  1473.   {
  1474.   int BlockRover, TempSent, LoopCount;
  1475.   /*
  1476.   * First, check for terminal failure.
  1477.   */
  1478.   if (TrError != TRAN_SUCCESS) return FALSE;
  1479.   /*
  1480.   * Process current character.
  1481.   */
  1482.   Twindow[CurWindow].buf[TrCount] = c;
  1483.   /*
  1484.   * Block is full, so clean up details in preparation for transmission.
  1485.   */
  1486.   if (++TrCount == SECTSIZE)
  1487.     {
  1488.     Twindow[CurWindow].ThisBlock = TrBlock;
  1489.     Twindow[CurWindow].ThisCRC = calcrc(Twindow[CurWindow].buf, SECTSIZE);
  1490.     Twindow[CurWindow].status = SECTOR_READY;   /* Set to go */
  1491.     /* TrBlock = (TrBlock + 1) % 256; line below should work -- see SendCmnBlk */
  1492.     TrBlock++;
  1493.     CurWindow = (CurWindow + 1) % 4;
  1494.     TrCount = 0;
  1495.  
  1496.     }
  1497.   /*
  1498.   * Check for responses from receiver.
  1499.   */
  1500.   WXResponses();
  1501.   /*
  1502.   * Now we need to send outstanding blocks.
  1503.   */
  1504.   for (    BlockRover = (LastSent + 1) % 4, TempSent = LastSent;
  1505.   BlockRover != LastSent; BlockRover = (BlockRover + 1) % 4)
  1506.     {
  1507.     if (Twindow[BlockRover].status != SECTOR_READY) break;
  1508.     SendCmnBlk(WXMDM, Twindow + BlockRover, sendWXchar, SECTSIZE);
  1509.     Twindow[BlockRover].status = SENT;
  1510.     TempSent = BlockRover;
  1511.     if (!gotCarrier())
  1512.       {
  1513.       break;
  1514.  
  1515.       }
  1516.  
  1517.     }
  1518.   LastSent = TempSent;
  1519.   /*
  1520.   * Now we need to check to see if the Twindow is "full"
  1521.   */
  1522.   for (LoopCount = 0; gotCarrier() && WindowFull() &&
  1523.   LoopCount < MAX_WX_ERRORS;
  1524.   LoopCount++)
  1525.     {
  1526.     startTimer(WORK_TIMER);
  1527.     do
  1528.     WXResponses();
  1529.     while (chkTimeSince(WORK_TIMER) < 10 && WindowFull());
  1530.     if (WindowFull())
  1531.     SendCmnBlk(WXMDM, Twindow + LastSent, sendWXchar, SECTSIZE);
  1532.  
  1533.     }
  1534.   /*
  1535.   * If the Twindow is still full at this point, then we've suffered some
  1536.   * sort of fatal error, and it's time to bomb out.
  1537.   */
  1538.   if (WindowFull() || !gotCarrier())
  1539.     {
  1540.     TrError = TRAN_FAILURE;
  1541.     return FALSE;
  1542.  
  1543.     }
  1544.   return TRUE;
  1545.  
  1546.   }
  1547. #endif
  1548. /*
  1549. * sendYMChar()
  1550. *
  1551. * This function sends a character using YMODEM protocol.
  1552. */
  1553. int sendYMChar(int c)
  1554.   {
  1555.   if (TrError != TRAN_SUCCESS)
  1556.   return FALSE;
  1557.   blk.buf[TrCount++] = c;
  1558.   if (TrCount != CurYBufSize)
  1559.   return TRUE;
  1560.   return SendYBlk();
  1561.  
  1562.   }
  1563. /*
  1564. * SendYBlk()
  1565. *
  1566. * This function sends a YMODEM block.
  1567. */
  1568. int SendYBlk()
  1569.   {
  1570.   blk.ThisBlock = TrBlock;
  1571.   blk.ThisCRC   = calcrc(blk.buf, CurYBufSize);
  1572.   return XYBlock(YMDM, CurYBufSize);
  1573.  
  1574.   }
  1575. /*
  1576. * SummonSysop()
  1577. *
  1578. * This function rings the sysop for ^T.
  1579. */
  1580. void SummonSysop()
  1581.   {
  1582.   int i;
  1583.   CallSysop = FALSE;
  1584.   DisableModem(FALSE);
  1585.   ReActivate_Window();  /* allow window to be activated and to the front */
  1586.   printf("SYSOP: System available!  Hit space!\n");
  1587.   for (i = 0; i < 12 && !KBReady(); i++)
  1588.     {
  1589.     onConsole = TRUE;
  1590.     printf("%c", BELL);
  1591.     onConsole = FALSE;
  1592.     startTimer(WORK_TIMER);
  1593.     while (!KBReady() && chkTimeSince(WORK_TIMER) < 10l)
  1594.     ;
  1595.  
  1596.     }
  1597.   if (KBReady())
  1598.     {
  1599.     getCh();
  1600.     printf("CONSOLE mode\n ");
  1601.     whichIO = CONSOLE;
  1602.     setUp(FALSE);
  1603.     ScrNewUser();
  1604.     warned  = FALSE;
  1605.     logMessage(BAUD, "", FALSE);
  1606.  
  1607.     }
  1608.   else
  1609.     {
  1610.     printf("No answer.  System back on MODEM.\n");
  1611.     EnableModem(FALSE);
  1612.  
  1613.     }
  1614.   givePrompt();
  1615.  
  1616.   }
  1617. /*
  1618. * Transmission()
  1619. *
  1620. * Starts protocols up.
  1621. * Note: This only handles XMODEM, WXMODEM, and YMODEM.
  1622. */
  1623. char Transmission(int protocol, char mode)  /* Transmission handler */
  1624.   {
  1625.   int Errors, m;
  1626.   if (!gotCarrier() && protocol != ASCII)
  1627.     {
  1628.     #ifdef NEED_NET_DEBUG_ERRORS
  1629.     if (inNet != NON_NET)
  1630.     splitF(netLog, "Error: Transmission() got carrier loss\n");
  1631.     #endif
  1632.     return CARR_LOSS;
  1633.  
  1634.     }
  1635.   if (protocol == ASCII) return TRAN_SUCCESS;
  1636.   if (mode == STARTUP)
  1637.     {
  1638.     GenTrInit();
  1639.     ByteCount = 0l;
  1640.     for (Errors = 0; Errors < ERRORMAX; Errors++)
  1641.       {
  1642.       m = receive(MINUTE);
  1643.       switch (m)
  1644.         {
  1645.         case CAN:
  1646.         if (cfg.BoolFlags.debug) splitF(netLog, "Transmission() CANned\n");
  1647.         return CANCEL;
  1648.         case ERROR:
  1649.         if (cfg.BoolFlags.debug) splitF(netLog, "Transmission() did not start\n");
  1650.         return NO_START;
  1651.         case NAK:
  1652.         TransProtocol = XMDM;
  1653.         DoCRC = FALSE;
  1654.         return TRAN_SUCCESS;
  1655.         #ifdef WXMODEM_AVAILABLE
  1656.         case 'W':
  1657.         if (protocol == WXMDM)
  1658.           {
  1659.           TransProtocol = WXMDM;
  1660.           return TRAN_SUCCESS;
  1661.  
  1662.           }
  1663.         break;
  1664.         #endif
  1665.         case 'C':
  1666.         if (protocol == YMDM)
  1667.           {
  1668.           /* Kludge for floopy performance */
  1669.           CurYBufSize = 1024;
  1670.           TransProtocol = YMDM;
  1671.           return TRAN_SUCCESS;
  1672.  
  1673.           }
  1674.         TransProtocol = XMDM;
  1675.         return TRAN_SUCCESS;
  1676.         default:
  1677.         if (cfg.BoolFlags.debug) splitF(netLog, "TrStart: -%c (0x%x)-\n", m, m);
  1678.  
  1679.         }
  1680.  
  1681.       }
  1682.     if (cfg.BoolFlags.debug) splitF(netLog, "returning NO_START on loop exit.\n");
  1683.     return NO_START;    /* If we make it out of the loop, error */
  1684.  
  1685.     }
  1686.   else
  1687.     {
  1688.     if (inNet == NON_NET) printf("\n");
  1689.     if (TrError != TRAN_SUCCESS)
  1690.       {
  1691.       splitF(netLog, "TranFin found TrError was bad immediately\n");
  1692.       return TrError;
  1693.  
  1694.       }
  1695.     if (TransProtocol == YMDM && TrCount < SECTSIZE)
  1696.     CurYBufSize = SECTSIZE;
  1697.     while (TrCount != 0)
  1698.       {
  1699.       (*Table[TransProtocol].method)(' ');
  1700.  
  1701.       }
  1702.     if (TrError != TRAN_SUCCESS)
  1703.       {
  1704.       splitF(netLog, "TranFin found TrError after buffer fill\n");
  1705.       return TrError;
  1706.  
  1707.       }
  1708.     if (Table[TransProtocol].CleanUp != NULL)
  1709.       {
  1710.       return (char) (*Table[TransProtocol].CleanUp)();
  1711.  
  1712.       }
  1713.     TransProtocol = ASCII;  /* Return to normal */
  1714.     return TRAN_SUCCESS;
  1715.  
  1716.     }
  1717.   }
  1718. #ifdef WXMODEM_AVAILABLE
  1719. /*
  1720. * WXResponses()
  1721. *
  1722. * Handles ACK/NAK and XON/XOFF for WXMODEM.
  1723. */
  1724. void WXResponses()
  1725.   {
  1726.   int rover, sig, old, SeqReceived;
  1727.   if (MIReady())
  1728.     {
  1729.     sig = recWXchar(1);
  1730.     switch (sig)
  1731.       {
  1732.       case XOFF:
  1733.       FlowControl();
  1734.       break;
  1735.       case ACK:
  1736.       case NAK:
  1737.       SeqReceived = recWXchar(5) & 0x03;
  1738.       if (sig == ACK)
  1739.         {
  1740.         rover = StartWindow;
  1741.         do
  1742.           {
  1743.           Twindow[rover].status = ACKED;
  1744.           old = rover;
  1745.           rover = (rover + 1) % 4;
  1746.  
  1747.           }
  1748.         while (old != SeqReceived);
  1749.         StartWindow = rover;    /* First block of Twindow */
  1750.  
  1751.         }
  1752.       else
  1753.         {
  1754.         /* NAK */
  1755.         LastSent = (SeqReceived == 0) ? 3 : (SeqReceived - 1);
  1756.         rover = SeqReceived;
  1757.         do
  1758.           {
  1759.           Twindow[rover].status = SECTOR_READY;
  1760.           rover = (rover + 1) % 4;
  1761.  
  1762.           }
  1763.         while (rover != CurWindow);
  1764.  
  1765.         }
  1766.       break;
  1767.  
  1768.       }
  1769.  
  1770.     }
  1771.  
  1772.   }
  1773. #endif
  1774. /*
  1775. * XYBlock()
  1776. *
  1777. * This function handles common work of XMODEM and YMODEM.
  1778. */
  1779. char XYBlock(int mode, int size)
  1780.   {
  1781.   int i, m;
  1782.   #ifdef NEED_NET_DEBUG
  1783.   splitF(netLog, "In XYBlock\n");
  1784.   #endif
  1785.   ByteCount += size;
  1786.   for (i = 0; i < ERRORMAX; i++)
  1787.     {
  1788.     SendCmnBlk(mode, &blk, outMod, size);
  1789.     while (MIReady()) inp();  /* clear line */
  1790.     m = receive(10);  /* wait 10 seconds for return ACK/NAK */
  1791.     if (m == ACK || m == CAN || !gotCarrier()) break;
  1792.     #ifdef NEED_NET_DEBUG_ERRORS
  1793.     if (inNet != NON_NET)
  1794.     splitF(netLog, "Tr Resend (m=%c [%x])\n", m, m);
  1795.     #endif
  1796.  
  1797.     }
  1798.   TrCksm  = TrCount = 0;
  1799.   TrBlock++;
  1800.   if (m == ACK)
  1801.     {
  1802.     #ifdef NEED_NET_DEBUG_ERRORS
  1803.     if (inNet != NON_NET)
  1804.     splitF(netLog, "Ack on block\n");
  1805.     #endif
  1806.     return TRUE;
  1807.  
  1808.     }
  1809.   TrError = TRAN_FAILURE;
  1810.   if (inNet == NON_NET) printf("Aborting\n ");
  1811.   else splitF(netLog, "XYBlock aborting (%s)\n", (gotCarrier()) ? "10 NAKs" :
  1812.   "carrier loss");
  1813.   return FALSE;
  1814.  
  1815.   }
  1816. /*
  1817. * XYClear()
  1818. *
  1819. * This function finishes XMODEM and YMODEM transmission.
  1820. */
  1821. int XYClear()
  1822.   {
  1823.   int i, m;
  1824.   for (i = 0; gotCarrier() && i < ERRORMAX; i++)
  1825.     {
  1826.     #ifdef NEED_NET_DEBUG
  1827.     splitF(netLog, "Sending EOT\n");
  1828.     #endif
  1829.     outMod(EOT);
  1830.     if ((m = receive(10)) == ACK)
  1831.     return TRAN_SUCCESS;
  1832.     if (m == CAN)
  1833.     return TRAN_FAILURE;
  1834.  
  1835.     }
  1836.   return TRAN_FAILURE;
  1837.  
  1838.   }
  1839. /*
  1840. * YMHdr()
  1841. *
  1842. * This function sends the header for a YMODEM BATCH transmission.
  1843. */
  1844. int YMHdr(long fileSize, char *filename)
  1845.   {
  1846.   extern int (*ITLFunc)(int c);
  1847.   TrBlock    = 0; /* One a kludge, two a kludge, three a kludge .. */
  1848.   ITLFunc = sendYMChar;
  1849.   mTrPrintf("%s", filename);
  1850.   mTrPrintf("%ld", fileSize);
  1851.   if (TrCount < 128)
  1852.   CurYBufSize = 128;
  1853.   if (TrCount != 128)
  1854.   for (; TrCount != 0 && sendYMChar(0); )
  1855.   ;
  1856.   else
  1857.   SendYBlk();
  1858.   if (TrError != TRAN_SUCCESS) return FALSE;
  1859.   if (strLen(filename) != 0)
  1860.   Transmission(YMDM, STARTUP);  /* now restart protocol *sigh* */
  1861.   return TrError == TRAN_SUCCESS;
  1862.  
  1863.   }
  1864. #ifdef NEED_NET_DEBUG_ERRORS
  1865. void DumpToFile(int LastReceived, int BufSize, CRC_TYPE tc, CRC_TYPE oc)
  1866.   {
  1867.   int i, j;
  1868.   FILE *fd;
  1869.   extern NetBuffer netBuf;
  1870.   if (strCmpU(netBuf.netName, "Images") == 0)
  1871.     {
  1872.     if ((fd = fopen("badsector", "a")) != NULL)
  1873.       {
  1874.       fprintf(fd, "Error on sector %d.  Their crc is %x, our's %x. Contents:\n", LastReceived, tc, oc);
  1875.       for (i = 0; i < BufSize; i += 16)
  1876.         {
  1877.         fprintf(fd, "%2x:", i);
  1878.         for (j = i; j < i + 16; j++)
  1879.         fprintf(fd, " %02x", DataBuf[j]);
  1880.         fprintf(fd, "   ");
  1881.         for (j = i; j < i + 16; j++)
  1882.         fprintf(fd, "%c", isprint(DataBuf[j]) ? DataBuf[j] : '.');
  1883.         fprintf(fd, "\n");
  1884.  
  1885.         }
  1886.       fprintf(fd, "\n");
  1887.       fclose(fd);
  1888.  
  1889.       }
  1890.  
  1891.     }
  1892.  
  1893.   }
  1894. #endif
  1895.